/*
 *    Copyright (c) 2018-2025, shenghua All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: shenghua
 */

package com.chen.base.utils;

import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.CodeSignature;
import org.aspectj.lang.reflect.MethodSignature;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 陈锦龙
 * @since 2022/3/16 15:30
 */
@UtilityClass
public class JoinPointUtil {

	/**
	 * 获取类上的注解
	 */
	public <A extends Annotation> A getClassAnnotation(JoinPoint point, Class<A> aClass) {
		return point.getTarget().getClass().getAnnotation(aClass);
	}

	/**
	 * 获取方法上的注解
	 */
	public <A extends Annotation> A getMethodAnnotation(JoinPoint point, Class<A> aClass) {
		return ((MethodSignature) point.getSignature()).getMethod().getAnnotation(aClass);
	}

	/**
     * 获取方法参数的相关信息，K：参数名 V：参数值
     */
    public Map<String, Object> paramsMap(JoinPoint point) {
        Object[] args = point.getArgs();
        String[] parameterNames = ((CodeSignature) point.getSignature()).getParameterNames();
        Map<String,Object> paramsMap = new HashMap<>(args.length);
        for (int i = 0; i < parameterNames.length; i++) {
            paramsMap.put(parameterNames[i], args[i]);
        }

        return paramsMap;
    }

	/**
	 * 获取spel表达式的参数值，如：#user.userId
	 * @param point JoinPoint
	 * @param paramName 参数名
	 * @return 值
	 */
    @SneakyThrows
	public Object getSpelVa(JoinPoint point, String paramName){
		Map<String, Object> paramsMap = paramsMap(point);
		if (paramName.contains("#") && paramName.contains(".")){
			int startIn = paramName.indexOf("#");
			int endIn = paramName.indexOf(".");
			// 对象名/属性名，如：#user.userId -> 对象名user，属性名userId
			String objectName = paramName.substring(startIn + 1, endIn);
			String attributeName = paramName.substring(endIn + 1);
			// 反射获取对象中属性值
			Object obj = paramsMap.get(objectName);
			Field field = obj.getClass().getDeclaredField(attributeName);
			field.setAccessible(true);
			return field.get(obj);
		}else if (paramName.contains("#")){
			return paramsMap.get(paramName.substring(1));
		}else {
			return paramName;
		}
	}
}
